package com.mlx.mylogin.impl;


import com.alibaba.fastjson.JSONObject;
import com.mlx.mylogin.base.Configuration;
import com.mlx.mylogin.base.HttpSnapshot;
import com.mlx.mylogin.base.LoginException;
import com.mlx.mylogin.inter.AbstractLoginManager;
import org.mlx.util.security.Hash;
import org.mlx.util.security.HexCipher;


import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.UUID;

public class JWTLoginManager extends AbstractLoginManager {

    private final String SECRET_KEY = UUID.randomUUID().toString().toUpperCase();

    // token字符串格式正则表达式
    private static final String TOKEN_FORMAT = "([a-fA-F0-9][a-fA-F0-9]){1,}\\.[0-9]{1,}\\.([a-fA-F0-9][a-fA-F0-9]){1,}";

    public JWTLoginManager(Configuration configuration) {
        super(configuration);
    }

    @Override
    protected String generateToken(HttpServletRequest request, Object user) {
        StringBuilder token = new StringBuilder();
        token.append(HexCipher.encryptString(JSONObject.toJSONString(user))).append(".");
        token.append(System.currentTimeMillis()).append(".");
        token.append(Hash.hash256String(token + SECRET_KEY));
        return token.toString();
    }


    @Override
    protected Object parseToken(HttpServletRequest request, String token) {
        verifyToken(token);
        String[] tokenItems = token.split("\\.");
        return JSONObject.parseObject(HexCipher.decryptToString(tokenItems[0]));
    }

    private void verifyToken(String token){
        if (token == null){
            throw new LoginException("未登录");
        }

        if (!verifyTokenFormat(token)){
            throw new LoginException("非法令牌格式");
        }

        if (!verifyTokenExpiration(token)){
            throw new LoginException("登录超时");
        }

        if (!verifyTokenSignature(token)){
            throw new LoginException("非法签证");
        }

    }

    private boolean verifyTokenFormat(String token) {
        return token.matches(TOKEN_FORMAT);
    }

    private boolean verifyTokenExpiration(String token) {
        long issueTime = Long.parseLong(token.split("\\.")[1]);
        return (issueTime + configuration.getTimeOut()) < System.currentTimeMillis();
    }

    private boolean verifyTokenSignature(String token) {
        String[] tokenItems = token.split("\\.");
        String signature = tokenItems[2];
        String signatureTemp = Hash.hash256String(tokenItems[0] + "." + tokenItems[1] + "." + SECRET_KEY);
        return signature.equals(signatureTemp);
    }


    @Override
    protected void refreshToken(HttpSnapshot httpSnapshot) {

        String token = httpSnapshot.getToken();
        String[] tokenItems = token.split("\\.");
        StringBuilder tokenTemp = new StringBuilder();
        tokenTemp.append(tokenItems[0]).append(".");
        tokenTemp.append(System.currentTimeMillis()).append(".");
        tokenTemp.append(Hash.hash256String(tokenTemp + SECRET_KEY));

        Cookie cookie = new Cookie(configuration.getTokenKey(), tokenTemp.toString());

        HttpServletResponse response = httpSnapshot.getResponse();
        response.addCookie(cookie);
    }

    @Override
    public <T> T getUser(Class<T> userClass) {
        return ((JSONObject) getUser()).toJavaObject(userClass);
    }
}
